<template>
  <div>
    <el-form
      v-if="filterOptions.length > 0"
      :model="queryParams"
      ref="queryRef"
      :inline="true"
      v-show="showSearch"
      label-width="90px"
    >
      <template v-for="item in filterOptions">
        <el-form-item :label="item.title" :prop="item.field">
          <template v-if="item.type === 'select' || item.type === 'radio'">
            <el-select
              v-model="queryParams[item.field]"
              :placeholder="`请选择${item.title}`"
              clearable
              size="small"
            >
              <el-option
                v-for="item in item.options"
                :key="+item.value"
                :label="item.label"
                :value="+item.value"
              >
              </el-option>
            </el-select>
          </template>
          <template v-else-if="item.type === 'daterange'">
            <el-date-picker
              size="small"
              style="width: 240px"
              v-model="queryParams[item.field]"
              value-format="yyyy-MM-dd HH:mm:ss"
              type="daterange"
              range-separator="-"
              start-placeholder="开始日期"
              end-placeholder="结束日期"
              :picker-options="pickerOptions"
            ></el-date-picker>
          </template>
          <template v-else>
            <el-input
              :id="item.field"
              v-model="queryParams[item.field]"
              :placeholder="`请输入${item.title}`"
              size="small"
            />
          </template>
        </el-form-item>
      </template>

      <el-form-item>
        <el-button
          type="primary"
          icon="el-icon-search"
          size="mini"
          @click="handleQuery"
          >搜索</el-button
        >
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery"
          >重置</el-button
        >
      </el-form-item>
    </el-form>

    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5" v-if="isShowButtonList">
        <el-button
          v-if="formOptions.length > 0"
          type="primary"
          size="mini"
          plain
          icon="Plus"
          @click="handleAdd"
          >新增</el-button
        >
      </el-col>
      <!-- <el-col :span="1.5" v-if="isShowButtonList">
        <el-button
          type="success"
          plain
          icon="Edit"
          :disabled="single"
          @click="handleUpdate"
          >修改</el-button
        >
      </el-col> -->
      <el-col :span="1.5" v-if="isShowButtonList">
        <el-button
          type="danger"
          plain
          size="mini"
          icon="Delete"
          :disabled="multiple"
          @click="handleDelete"
          >删除</el-button
        >
      </el-col>
      <slot name="toolbar"></slot>
      <!-- <right-toolbar
        v-model:showSearch="showSearch"
        @queryTable="getList"
      ></right-toolbar> -->
    </el-row>
      <slot name="toolbarBottom"></slot>
    <el-table
      v-loading="loading"
      :data="list"
      @selection-change="handleSelectionChange"
    >
      <el-table-column type="selection" width="55" align="center" />
      <el-table-column
        v-if="isShowIdColumn"
        :prop="idColumnName"
        width="60"
        label="ID"
        align="center"
      />
      <template v-for="item in TableOptions">
        <template v-if="item.slot">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
          >
            <template #default="scope">
              <slot :name="item.slot" v-bind="scope"></slot>
            </template>
          </el-table-column>
        </template>
        <template v-else-if="item.actions">
          <el-table-column
            label="操作"
            align="center"
            v-bind="item.props"
            width="100px"
            fixed="right"
          >
            <template #default="scope">
              <template v-for="act in item.actions">
                <el-button
                  v-if="act.filter ? act.filter(scope.row) : true"
                  type="text"
                  @click="
                    act.type === 'edit'
                      ? handleUpdate(scope.row, act.beforeCallback)
                      : act.type === 'delete'
                      ? handleDelete(scope.row)
                      : act.type === 'detail'
                      ? handleDetail(scope.row,act.beforeCallback)
                      : act.click && act.click(scope.row)
                  "
                >
                  {{
                    act.type === "edit"
                      ? "编辑"
                      : act.type === "delete"
                      ? "删除"
                      : act.type === "detail"
                      ? "详情"
                      : act.text
                  }}
                </el-button>
              </template>
            </template>
          </el-table-column>
        </template>
        <template v-else-if="item.type === 'img'">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
          >
            <template #default="scope">
              <el-image
                :src="
                  item.render
                    ? item.render(scope.row)[0]
                    : scope.row[item.field]
                "
                :preview-src-list="
                  item.render ? item.render(scope.row) : [scope.row[item.field]]
                "
                :style="item.style || { width: '70px', maxHeight: '100px' }"
                fit="cover"
              />
            </template>
          </el-table-column>
        </template>

        <template v-else-if="item.type === 'file'">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
          >
            <template #default="scope">
              <el-image
                v-if="item.render && item.render(scope.row).length > 0"
                :src="
                  item.render
                    ? item.render(scope.row)[0]
                    : scope.row[item.field]
                "
                :preview-src-list="
                  item.render ? item.render(scope.row) : [scope.row[item.field]]
                "
                :style="item.style || { width: '70px', maxHeight: '100px' }"
                fit="cover"
              />
              <span v-else-if="scope.row[item.field]"> <el-link target="_blank" type="primary" v-for="(item,index) in scope.row[item.field].split(',')" :key="index" :href="item"> 查看附件</el-link></span>
              <span v-else>无附件</span>
            </template>
          </el-table-column>
        </template>
        <template v-else-if="item.render">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
            align="center"
          >
            <template #default="scope">
              {{ item.render(scope.row) }}
            </template>
          </el-table-column>
        </template>
        <template v-else-if="item.type === 'radio' || item.type === 'select'">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
            align="center"
          >
            <template #default="scope">
              <dict-tag
                :options="item.options"
                :value="scope.row[item.field]"
              />
            </template>
          </el-table-column>
        </template>
        <template v-else-if="item.type === 'date' || item.type === 'dateTime'">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
            align="center"
          >
            <template #default="scope">
              <span>{{
                parseTime(
                  scope.row[item.field],
                  item.type === "date" ? "{y}-{m}-{d}" : item.dateFormat
                )
              }}</span>
            </template>
          </el-table-column>
        </template>
        <template v-else-if="item.type === 'desc'">
          <el-table-column
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
          >
            <template #default="scope">
              <div class="table-pro__desc">
                {{ scope.row[item.field] }}
              </div>
            </template>
          </el-table-column>
        </template>
        <template v-else>
          <el-table-column
            align="center"
            :prop="item.field"
            :label="item.title"
            v-bind="item.props"
            min-width="100px"
          />
        </template>
      </template>
    </el-table>

    <pagination
      v-show="total > 0"
      :total="total"
      :page.sync="queryParams.pageNum"
      :limit.sync="queryParams.pageSize"
      @pagination="getList"
    />

    <el-dialog
      :title="title"
      :visible.sync="open"
      :width="formDialogWidth"
      :close-on-click-modal="false"
    >
      <el-form
        ref="formRef"
        :model="form"
        label-width="100px"
        :rules="rules"
        :validate-on-rule-change="false"
      >
        <el-form-item
          :label="`${item.title}：`"
          :prop="item.field"
          v-for="item in formOptions"
          :key="item.title"
        >
          <template v-if="item.formSlot">
            <slot :name="item.formSlot" v-bind="item"></slot>
          </template>
          <template v-else-if="item.type === 'date'">
            <el-date-picker
              v-model="form[item.field]"
              type="date"
              :placeholder="`请输入${item.title}`"
              value-format="yyyy-MM-dd HH:mm:ss"
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
            />
          </template>
          <template v-else-if="item.type === 'radio'">
            <el-radio-group
              v-model="form[item.field]"
              v-bind="item.formProps"
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
              @change="
                (val) => {
                  handleRadioChange(val, item.change);
                }
              "
            >
              <el-radio
                :label="radio.value"
                v-for="(radio, index) in item.options"
                :key="index"
                >{{ radio.label }}</el-radio
              >
            </el-radio-group>
          </template>
          <template v-else-if="item.type === 'select'">
            <el-select
              v-model="form[item.field]"
              :placeholder="`请选择${item.title}`"
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
              v-bind="item.formProps"
              filterable
            >
              <el-option
                v-for="(item, index) in item.options"
                :key="index"
                :label="item.label"
                :value="item.value"
              >
              </el-option>
            </el-select>
          </template>
          <template v-else-if="item.type === 'cascader'">
            <el-cascader
              :options="item.options || []"
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
              v-model="form[item.field]"
              v-bind="item.formProps"
            />
          </template>
          <template v-else-if="item.type === 'img'">
            <image-upload type="flag" v-model:modelValue="form[item.field]" :disabled="(curState == 1) || (curState == 2 && item.disabled)"/>
          </template>
          <template v-else-if="item.type === 'file'">
            <fileUpload :fileSize="10" :fileType="fileType" v-model:modelValue="form[item.field]" :disabled="(curState == 1) || (curState == 2 && item.disabled)"/>
          </template>
          <template v-else-if="item.type === 'number'">
            <el-input-number
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
              v-model="form[item.field]"
              :placeholder="`请输入${item.title}`"
              style="width: 160px"
            />
          </template>
          <template v-else-if="item.type === 'department'">
            <treeselect
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
              v-model="form[item.field]"
              :options="deptOptions"
              :placeholder="`请输入${item.title}`"
              @select="
                (val) => {
                  onDepartmentChange(val, item.field);
                }
              "
            />
          </template>
          <template v-else-if="item.type === 'user'">
            <el-select
              v-model="form[item.field]"
              :placeholder="`请选择${item.title}`"
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
              v-bind="item.formProps"
              filterable
              @change="
                (val) => {
                  onCustomSelectChange(
                    val,
                    item.field,
                    userList,
                    'userId',
                    'userName'
                  );
                }
              "
            >
              <el-option
                v-for="(item, index) in userList"
                :key="index"
                :label="item.nickName"
                :value="item.userId"
              >
              </el-option>
            </el-select>
          </template>
          <template v-else>
            <el-input
              v-model="form[item.field]"
              :placeholder="`请输入${item.title}`"
              v-bind="item.formProps"
              :disabled="(curState == 1) || (curState == 2 && item.disabled)"
            />
          </template>
        </el-form-item>
      </el-form>
      <template #footer v-if="curState != 1">
        <span class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import { deptTreeSelect, listUser } from "@/api/system/user";
import Treeselect from "@riophae/vue-treeselect";
import "@riophae/vue-treeselect/dist/vue-treeselect.css";
export default {
  name: "TablePro",
  components: { Treeselect },
  props: {
    columns: {
      type: Array,
      default: [],
    },
    tableRequestFn: {
      type: Function,
      default: () => {},
    },
    createFn: {
      type: Function,
      default: () => {},
    },
    updateFn: {
      type: Function,
      default: () => {},
    },
    deleteFn: {
      type: Function,
      default: () => {},
    },
    closeModalCallback: {
      type: Function,
      default: () => {},
    },
    addBtnCallback: {
      type: Function,
      default: () => {},
    },
    beforeSubmitCallback: {
      type: Function
    },
    dialogTitle: {
      type: String,
      default: "",
    },
    tableParams: {
      type: Object,
      default: () => {},
    },
    formParams: {
      type: Object,
      default: () => {},
    },
    defaultQueryParams: {
      type: Object,
      default: () => {},
    },
    onReset: {
      type: Function,
      default: () => {},
    },
    formDialogWidth: {
      type: String,
      default: "600px",
    },
    isShowIdColumn: {
      type: Boolean,
      default: true,
    },
    idColumnName: {
      type: String,
      default: "id",
    },
    isShowButtonList: {
      type: Boolean,
      default: true,
    },
    isAutoFetch: {
      type: Boolean,
      default: true,
    },
  },
  data() {
    return {
      fileType:["doc", "xls", "ppt", "txt", "pdf",'png', 'jpg', 'jpeg'],
      curState:1,//1详情2更新3新增
      curId: undefined,
      list: [],
      ids: [],
      loading: true,
      single: true,
      multiple: true,
      showSearch: true,
      total: 0,
      title: "",
      open: false,
      countryOptions: [],
      actorOptions: [],
      userList: [],
      deptOptions: undefined,
      form: { ...this.formParams },
      queryParams: {
        status: undefined,
        pageNum: 1,
        pageSize: 10,
        ...this.defaultQueryParams
      },
    };
  },
  computed: {
    rules() {
      const obj = {};
      this.columns.forEach((value) => {
        if (Object.prototype.toString.call(value.add) === "[object Array]") {
          obj[value.field] = value.add;
        }
      });
      return obj;
    },
    TableOptions() {
      return this.columns
        .filter((value) => !value.hidden)
        .sort((a, b) => a.sort - b.sort);
    },
    filterOptions() {
      return this.columns.filter((value) => value.search);
    },
    formOptions() {
      return this.columns.filter((value) => value.add);
    },
    dateRangeSearchOptions() {
      return this.columns.filter(
        (value) => value.search && value.type == "daterange"
      );
    },
    pickerOptions() {
      return {
        shortcuts: [
          {
            text: "最近一周",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              end.setTime(end.getTime() + 3600 * 1000 * 24 * 7);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近一个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              end.setTime(end.getTime() + 3600 * 1000 * 24 * 30);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近二个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              end.setTime(end.getTime() + 3600 * 1000 * 24 * 60);
              picker.$emit("pick", [start, end]);
            },
          },
          {
            text: "最近三个月",
            onClick(picker) {
              const end = new Date();
              const start = new Date();
              end.setTime(end.getTime() + 3600 * 1000 * 24 * 90);
              picker.$emit("pick", [start, end]);
            },
          },
        ],
      };
    },
  },
  methods: {
    toUpperCase(str) {
      return str.charAt(0).toUpperCase() + str.slice(1);
    },
    // 处理时间段
    processDateRange() {
      var result = { ...this.queryParams };
      this.dateRangeSearchOptions.forEach((item) => {
        if (result[item.field] && result[item.field].length == 2)
          this.addDateRange(
            result,
            result[item.field],
            this.toUpperCase(item.field)
          );
        delete result[item.field];
      });
      return result;
    },
    async getList(params = {}) {
      this.loading = true;
      try {
        var tempQueryParams = this.processDateRange();
        const data = await this.tableRequestFn({
          ...tempQueryParams,
          ...this.tableParams,
          ...params,
        });
        this.list = data.rows;
        this.total = data.total;
      } finally {
        this.loading = false;
      }
    },
    reset() {
      this.form = { ...this.formParams };
      this.resetForm("formRef");
      this.curId = undefined;
      this.onReset()
    },
    handleAdd() {
      this.reset();
      this.curState = 3
      this.open = true;
      this.title = "添加" + this.dialogTitle;
      this.addBtnCallback();
      this.$emit("curState",this.curState)
    },
    async handleUpdate(row, beforeCallback) {
      this.reset();
      this.curState = 2
      this.$emit("curState",this.curState)
      const id = row[this.idColumnName] || this.ids[0];
      this.open = true;
      let item = row[this.idColumnName]
        ? row
        : this.list.find((value) => value[this.idColumnName] === id);
      if (beforeCallback) {
        item = await beforeCallback(item);
      }
      this.curId = id;
      this.form = { ...item };
      this.title = "修改" + this.dialogTitle;
    },
    handleDelete(row) {
      const id = row[this.idColumnName] || this.ids;
      this.$modal
        .confirm('是否确认删除"' + id + '"的数据项？')
        .then(async () => {
          try {
            await this.deleteFn(id);
            this.$modal.msgSuccess("删除成功");
            await this.getList();
          } catch (e) {
            console.warn(e);
          }
        });
    },
    async handleDetail(row,beforeCallback) {
      this.reset();
      this.curState = 1
      this.$emit("curState",this.curState)
      const id = row[this.idColumnName] || this.ids[0];
      this.open = true;
      let item = row[this.idColumnName]
        ? row
        : this.list.find((value) => value[this.idColumnName] === id);
      if (beforeCallback) {
        item = await beforeCallback(item);
      }
      this.curId = id;
      this.form = { ...item };
      this.title = this.dialogTitle + "详情";
    },
    submitForm() {
      if(this.beforeSubmitCallback){
        this.form = this.beforeSubmitCallback(this.form)
      }
      console.log(this.form);
      this.$refs["formRef"].validate(async (valid) => {
        if (valid) {
          try {
            if (this.form[this.idColumnName]) {
              await this.updateFn(this.form);
            } else {
              await this.createFn(this.form);
            }
            this.$modal.msgSuccess("成功");
            this.open = false;
            await this.getList();
          } catch (e) {
            console.warn(e);
          }
        }
      });
    },
    cancel() {
      this.open = false;
      this.reset();
      this.closeModalCallback();
    },
    handleSelectionChange(selection) {
      this.ids = selection.map((item) => item[this.idColumnName]);
      this.single = selection.length !== 1;
      this.multiple = !selection.length;
    },
    handleRadioChange(val, change) {
      change && change(val);
    },
    handleQuery() {
      this.queryParams.pageNum = 1;
      this.getList();
    },
    resetQuery() {
      this.resetForm("queryRef");
      this.handleQuery();
    },
    // 1  userId [{}] user userName
    onCustomSelectChange(val, field, list, idField, nameField) {
      var temp = list.find((value) => {
        return value[idField] == val;
      });
      this.form[field.slice(0, -2)] = temp[nameField];
    },

    onDepartmentChange(val, field) {
      this.form[field.slice(0, -2)] = val.label;
    },
    getDeptTree() {
      deptTreeSelect().then((response) => {
        this.deptOptions = response.data;
      });
    },
    getUserList() {
      listUser().then((response) => {
        this.userList = response.rows;
      });
    },
  },
  mounted() {
    if (this.isAutoFetch) {
      this.getList();
    }
  },
  created() {
    this.getDeptTree();
    this.getUserList();
  },
};
</script>

<style lang="scss" scoped>
.table-pro {
  &__desc {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    overflow: hidden;
  }
}
</style>
